package com.kf.controller;

import com.kf.aop.LogOperation;
import com.kf.config.RedisUtil;
import com.kf.config.RsaUtil;
import com.kf.config.SecurityUser;
import com.kf.config.shiro.PhoneCodeToken;
import com.kf.handler.MyException;
import com.kf.pojo.*;
import com.kf.pojo.form.NoticeForm;
import com.kf.pojo.form.PhoneCode;
import com.kf.pojo.form.SelectForm;
import com.kf.pojo.form.UserForm;
import com.kf.service.*;
import com.kf.util.MD5Utils;
import com.kf.util.R;

import com.kf.util.ResultCode;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 登录控制器
 *
 * @author Honey
 * @date 2022/12/23
 */
@CrossOrigin(allowedHeaders = "*",origins={"*"},allowCredentials = "true",maxAge = 3600)
@RestController
@RequestMapping("/login")
@Api("登录")
public class LoginController {


    @Resource
    UserService userService;
    @Resource
    private RedisUtil redisUtil;

    @Resource
    PermissionService permissionService;
    @Resource
    RsaUtil rsaUtil;

    @Resource
    SysDictTypeService sysDictTypeService;
    @Resource
    TeacherService teacherService;
    @Resource
    CommonService commonService;
    public static ThreadLocal<UserForm> stringThreadLocal = new ThreadLocal<>();
    @PostMapping("/user")
    @ApiOperation("登录")
    @LogOperation("登录")
    public R login(@Validated @RequestBody UserForm userForm, HttpServletRequest request, Model model){
        String password = rsaUtil.decrypt(userForm.getPassword());
        User user1 = userService.queryUserByName(userForm.getUsername());

        UsernamePasswordToken token = new UsernamePasswordToken(userForm.getUsername(), password);
        userForm.setPassword(password);

        stringThreadLocal.set(userForm);
        if(user1==null){
            return R.error(ResultCode.USER_LOGIN_ERROR);
        }
        if(!MD5Utils.encrypt(user1.getUsername(), password).equals(user1.getPassword())){
            userForm.setStatus(0);
            return R.error(ResultCode.USER_LOGIN_ERROR);
        }
        try {
            Subject subject = SecurityUtils.getSubject();
            String csrfToken = MD5Utils.MD5Encode();
            HttpSession session = request.getSession();
            session.setAttribute("csrf_Token",csrfToken);
            User user = userService.queryUserByName(userForm.getUsername());
            subject.login(token);
            redisUtil.set(user.getUsername(), csrfToken,60*60*48);
            redisUtil.set(session.getId(),user,60*60*48);
            HashMap<String, String> map = new HashMap<>();
            map.put("csrfToken",csrfToken);
            map.put("userId",String.valueOf(user.getUserId()));

            if("123456".equals(userForm.getPassword())){
                    return R.okey(ResultCode.SUCCESS_FIRST).put("data",map);
            }else{
                return R.okey(ResultCode.SUCCESS).put("data",map);
            }
        }  catch (UnknownAccountException e) {
            model.addAttribute("msg","用户名错误");
            return R.error(ResultCode.USER_LOGIN_ERROR);
        }catch (IncorrectCredentialsException e) {
            model.addAttribute("msg","密码错误");
            return R.error(ResultCode.USER_LOGIN_ERROR);
        }

    }
    @PostMapping("/login/perms")
    public R loginPerm(HttpServletRequest request) throws MyException {

        User user = SecurityUser.getUser();
        if(request.getHeader("csrfToken")!=null){
            List<Permission> myPerms = permissionService.findMyPerms(user);
            List<Permission> permissions = permissionService.listToTree(myPerms);
            List<Permission> perIdList=new ArrayList<>();
            List<Permission> permissionList = permissionService.treeToList(permissions,perIdList);
            List<Permission> permissionList1=new ArrayList<>();
            for (Permission permission : permissionList) {
                if(permission.getBton()==0){
                    permissionList1.add(permission);
                }
            }
            List<Permission> permissions1 = permissionService.listToTree(permissionList1);
            return R.okey(ResultCode.SUCCESS).put("data",permissions1);
        }else{
            return R.error(ResultCode.TOKEN_ERROR);
        }

    }




    @PostMapping("/logout")
    @LogOperation("退出")
    public R logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        redisUtil.del("token");
        return R.ok("login");
    }


    @GetMapping("/public")
    @ApiOperation("获取公钥")
    public R getPublic(){

        String aPublic = (String) redisUtil.get("public");
        return R.okey(ResultCode.SUCCESS).put("data",aPublic);

    }
    @GetMapping("/all/dicts")
    @ApiOperation("获取字典类型")
    public R allDict(){

        List<SysDictType> sysDictTypes = sysDictTypeService.selectData();
        return R.okey(ResultCode.SUCCESS).put("data",sysDictTypes);

    }
    @GetMapping("/btons")
    @ApiOperation("获取按钮")
    public R myBton(HttpServletRequest request){

        User user = SecurityUser.getUser();
        if(request.getHeader("csrfToken")!=null){

            List<Permission> myPerms = permissionService.findMyPerms(user);
            List<Permission> permIdList=new ArrayList<>();
            List<Permission> permissionList = permissionService.treeToList(myPerms, permIdList);

            List<String> myBton=new ArrayList<>();
            for (Permission myPerm : permissionList) {
                myPerm.setChildren(null);
                if(myPerm.getBton()==1){
                    myBton.add(myPerm.getPerms());
                }
            }
            return R.okey(ResultCode.SUCCESS).put("data",myBton);
        }else{
            return R.error(ResultCode.TOKEN_ERROR);
        }
    }
    @GetMapping("/department/teacher")
    @ApiOperation("拿到登录用户所在学院的所有老师")
    public R getTeacher(){
    try {
        User user = SecurityUser.getUser();
        List<Teacher> teachers = teacherService.selectList(user);
        List<String> teacherList=new ArrayList<>();
        for (Teacher teacher : teachers) {
            User user1 = userService.getById(teacher.getUserId());
            String usernameName=user1.getUsername()+" "+teacher.getTeaName();
            teacherList.add(usernameName);
        }
        return R.okey(ResultCode.SUCCESS).put("data",teacherList);
        }catch (Exception e){
            return R.error(ResultCode.USER_SELECT_ERROR);
        }
    }


    @GetMapping("/student/teacher/number")
    @ApiOperation("拿到登录用户所在学院的所有老师人数，学生人数")
    public R getDeStudent(){
        try {
            User user = SecurityUser.getUser();
            int students = userService.countStuByDepartmen(user);
            int teachers = userService.countTeaByDepartmen(user);
            Map<String,Integer> map=new HashMap<>();
            map.put("students",students);
            map.put("teachers",teachers);
            return R.okey(ResultCode.SUCCESS).put("data",map);
        }catch (Exception e){
            return R.error(ResultCode.USER_SELECT_ERROR);
        }
    }


    @PostMapping("/show/notices")
    @ApiOperation("拿到公告信息")
    public R getMyNotice(@Validated @RequestBody SelectForm selectForm) throws IOException {
        User user = SecurityUser.getUser();
        List<NoticeForm> myNotice = commonService.getMyNotice(selectForm.getName(), user);

        return R.ok().put("data",myNotice);
    }


    @PostMapping("/phone")
    @ApiOperation("手机登录")
    @LogOperation("手机登录")
    public R phoneLogin(@Validated @RequestBody PhoneCode phoneCode, HttpServletRequest request){
        PhoneCodeToken phoneCodeToken = new PhoneCodeToken(phoneCode.getPhone());
        if(redisUtil.hasKey(phoneCode.getPhone())){

            UserForm userForm = new UserForm();
            userForm.setUsername("no");
            stringThreadLocal.set(userForm);
            if(!phoneCode.getCode().equals(redisUtil.get(phoneCode.getPhone()))){
                return R.error(ResultCode.CODE_ERROR);
            }
        }else {
            UserForm userForm = new UserForm();
            userForm.setUsername("no");
            stringThreadLocal.set(userForm);
            return R.error(ResultCode.CODE_ERROR);
        }
        User user1 = userService.findByPhone(phoneCode.getPhone());
        if(user1==null){
            UserForm userForm = new UserForm();
            userForm.setUsername("no");
            stringThreadLocal.set(userForm);
            return R.error(ResultCode.PHONE_ERROR);
        }else {
            UserForm userForm = new UserForm();
            userForm.setUsername(user1.getUsername());
            userForm.setStatus(1);
            stringThreadLocal.set(userForm);
        }

        try {
            Subject subject = SecurityUtils.getSubject();
            String csrfToken = MD5Utils.MD5Encode();
            HttpSession session = request.getSession();
            session.setAttribute("csrf_Token",csrfToken);
            User user = userService.findByPhone(phoneCode.getPhone());
            subject.login(phoneCodeToken);
            redisUtil.set(user.getUsername(), csrfToken,60*60*10);
            redisUtil.set(session.getId(),user,60*60*10);
            HashMap<String, String> map = new HashMap<>();
            map.put("csrfToken",csrfToken);
            map.put("userId",String.valueOf(user.getUserId()));
            String encrypt = MD5Utils.encrypt(user.getUsername(), "123456");
            if(encrypt.equals(user.getPassword())){
                return R.okey(ResultCode.SUCCESS_FIRST).put("data",map);
            }else{
                return R.okey(ResultCode.SUCCESS).put("data",map);
            }


        }  catch (UnknownAccountException | IncorrectCredentialsException e) {

            return R.error(ResultCode.USER_LOGIN_ERROR);
        }


    }
}

